home *** CD-ROM | disk | FTP | other *** search
/ Mixa 155: Dogs / MIXA 155: Dogs.iso / pc / Viewer / BROWSER(W) / フィルタ / PDF / LIB / gs_ttf.ps < prev    next >
Encoding:
Text File  |  2002-10-29  |  27.0 KB  |  920 lines

  1. %    Copyright (C) 1996, 2000 Aladdin Enterprises.  All rights reserved.
  2. % This software is licensed to a single customer by Artifex Software Inc.
  3. % under the terms of a specific OEM agreement.
  4.  
  5. % $RCSfile: gs_ttf.ps,v $ $Revision: 1.13 $
  6. % Support code for direct use of TrueType fonts.
  7. % (Not needed for Type 42 fonts.)
  8.  
  9. % Note that if you want to use this file without including the ttfont.dev
  10. % option when you built Ghostscript, you will need to load the following
  11. % files before this one:
  12. %    lib/gs_mgl_e.ps
  13. %    lib/gs_mro_e.ps
  14. %    lib/gs_wan_e.ps
  15.  
  16. % Thanks to B. Jackowski and GUST (the Polish TeX Users' Group) for
  17. % the glyf-splitting code.
  18.  
  19. % ---------------- Font loading machinery ---------------- %
  20.  
  21. % Augment the FONTPATH machinery so it recognizes TrueType fonts.
  22.  
  23. /.scanfontheaders where {
  24.   pop /.scanfontheaders [
  25.    .scanfontheaders aload pop (\000\001\000\000*) (true*)
  26.   ] def
  27. } if
  28.  
  29. % <file> <key> .findfontvalue <value> true
  30. % <file> <key> .findfontvalue false
  31. % Closes the file in either case.
  32. /.findnonttfontvalue /.findfontvalue load def
  33. /.findfontvalue {
  34.   1 index read pop 2 index 1 index unread
  35.   dup 0 eq exch (t) 0 get eq or {
  36.         % If this is a font at all, it's a TrueType font.
  37.     dup /FontType eq {
  38.       pop closefile 42 true
  39.     } {
  40.       dup /FontName eq { pop .findttfontname } { pop closefile false } ifelse
  41.     } ifelse
  42.   } {
  43.         % Not a TrueType font.
  44.     .findnonttfontvalue
  45.   } ifelse
  46. } bind def
  47.  
  48. % <file> .findttfontname <fname> true
  49. % <file> .findttfontname false
  50. % Closes the file in either case.
  51. /.findttfontname {
  52.   .loadttfonttables
  53.   tabdict /name .knownget {
  54.     dup 8 getu32 f exch setfileposition
  55.     12 getu32 string f exch readstring pop
  56.     6 findname
  57.   } {
  58.     false
  59.   } ifelse
  60.   f closefile end end
  61. } bind def
  62.  
  63. % Load a font file that might be a TrueType font.
  64.  
  65. % <file> .loadfontfile -
  66. /.loadnonttfontfile /.loadfontfile load def
  67. /.loadfontfile {
  68.   dup read pop 2 copy unread 0 eq {
  69.         % If this is a font at all, it's a TrueType font.
  70.     .loadttfont pop
  71.   } {
  72.         % Not a TrueType font.
  73.     .loadnonttfontfile
  74.   } ifelse
  75. } bind def
  76.  
  77. % ---------------- Automatic Type 42 generation ---------------- %
  78.  
  79. % Load a TrueType font from a file as a Type 42 PostScript font.
  80. % The thing that makes this really messy is the handling of encodings.
  81. % There are 2 interacting tables that affect the encoding:
  82. %       'cmap' provides multiple maps from character codes to glyph indices
  83. %       'post' maps glyph indices to glyph names (if present)
  84. % What we need to get out of this is:
  85. %       Encoding mapping character codes to glyph names
  86. %         (the composition of cmap and post)
  87. %       CharStrings mapping glyph names to glyph indices
  88. %         (the inverse of post)
  89. % If the post table is missing, we have to take a guess based on the cmap
  90. % table.
  91.  
  92. /.loadttfontdict 50 dict dup begin
  93.  
  94. /orgXUID AladdinEnterprisesXUID def
  95. /maxstring 32000 def    % half the maximum length of a PostScript string,
  96.             % must be a multiple of 4 (for hmtx / loca / vmtx)
  97.  
  98. % Define the Macintosh standard mapping from characters to glyph indices.
  99. /MacRomanEncoding dup .findencoding def
  100. /MacGlyphEncoding dup .findencoding def
  101.  
  102. % Invert the MacRomanEncoding.
  103. /.romanmacdict 300 dict
  104. 0 1 MacRomanEncoding length 1 sub {
  105.   MacRomanEncoding 1 index get
  106.         % Stack: dict index charname
  107.   dup /.notdef ne {
  108.     exch 2 index 2 index .knownget {
  109.       dup type /arraytype eq {
  110.     [ exch aload pop counttomark 2 add -1 roll ]
  111.       } {
  112.     exch 2 array astore
  113.       } ifelse
  114.     } if 2 index 3 1 roll put
  115.   } {
  116.     pop pop
  117.   } ifelse
  118. } for def
  119.  
  120. % Define remapping for misnamed glyphs in TrueType 'post' tables.
  121. % There are probably a lot more than this!
  122. /postremap mark
  123.   /Cdot /Cdotaccent
  124.   /Edot /Edotaccent
  125.   /Eoverdot /Edotaccent
  126.   /Gdot /Gdotaccent
  127.   /Ldot /Ldotaccent
  128.   /Zdot /Zdotaccent
  129.   /cdot /cdotaccent 
  130.   /edot /edotaccent 
  131.   /eoverdot /edotaccent
  132.   /gdot /gdotaccent 
  133.   /ldot /ldotaccent
  134.   /zdot /zdotaccent 
  135. .dicttomark readonly def
  136.  
  137. % ---- Utilities ---- %
  138.  
  139. % Define a serial number for creating unique XUIDs for TrueType fonts.
  140. % We used to use the checkSumAdjustment value from the font, but this is
  141. % not reliable, since some fonts don't set it correctly.
  142. % Note that we must do this in a string to make it immune to save/restore.
  143. /xuidstring <80000000> def
  144. /curxuid {        % - curxuid <int>
  145.   0 xuidstring { exch 8 bitshift exch add } forall
  146. } bind def
  147. /nextxuid {        % - nextxuid -
  148.   3 -1 0 {
  149.     xuidstring 1 index 2 copy get dup 255 ne {
  150.       1 add put pop exit
  151.     } if pop 0 put pop
  152.   } for
  153. } bind def
  154.  
  155. % <string> <index> getu16 <integer>
  156. /getu16 {
  157.   2 copy get 8 bitshift 3 1 roll 1 add get add
  158. } bind def
  159.  
  160. % <string> <index> gets16 <integer>
  161. /gets16 {
  162.   getu16 16#8000 xor 16#8000 sub
  163. } bind def
  164.  
  165. % <string> <index> getu32 <integer>
  166. /getu32 {
  167.   2 copy getu16 16 bitshift 3 1 roll 2 add getu16 add
  168. } bind def
  169.  
  170. % <string> <index> gets32 <integer>
  171. /gets32 {
  172.   2 copy gets16 16 bitshift 3 1 roll 2 add getu16 add
  173. } bind def
  174.  
  175. % <string> <index> <integer> putu16 -
  176. /putu16 {
  177.   3 copy -8 bitshift put
  178.   exch 1 add exch 16#ff and put
  179. } bind def
  180.  
  181. % <string> <index> <integer> putu32 -
  182. /putu32 {
  183.   3 copy -16 bitshift putu16
  184.   exch 2 add exch 16#ffff and putu16
  185. } bind def
  186.  
  187. % <nametable> <nameid> findname <string> true
  188. % <nametable> <nameid> findname false
  189. /findname {
  190.   DEBUG { (findname: ) print dup =only  } if
  191.   false 3 1 roll 0 1 3 index 2 getu16 1 sub {
  192.         % Stack: false table id index
  193.     12 mul 6 add 2 index exch 12 getinterval
  194.     dup 6 getu16 2 index eq {
  195.         % We found the name we want.
  196.       exch pop
  197.         % Stack: false table record
  198.       dup 10 getu16 2 index 4 getu16 add
  199.       1 index 8 getu16 4 -1 roll 3 1 roll getinterval exch
  200.         % Stack: false string record
  201.         % Check for 8- vs. 16-bit characters.
  202.       is2byte { string2to1 } if true null 4 -1 roll exit
  203.     } if pop
  204.   } for pop pop
  205.   DEBUG {
  206.     dup { ( = ) print 1 index == } { ( not found) = } ifelse
  207.   } if
  208. } bind def
  209.  
  210. % <namerecord> is2byte <bool>
  211. /is2byte {
  212.   dup 0 getu16 {
  213.     { pop true }        % Apple Unicode
  214.     { pop false }        % Macintosh Script manager
  215.     { 1 getu16 1 eq }        % ISO
  216.     { 1 getu16 1 eq }        % Microsoft
  217.   } exch get exec
  218. } bind def
  219.  
  220. % <string2> string2to1 <string>
  221. /string2to1 {
  222.   dup length 2 idiv string dup
  223.   0 1 3 index length 1 sub {
  224.     3 index 1 index 2 mul 1 add get put dup
  225.   } for pop exch pop
  226. } bind def
  227.  
  228. % <array> <lt-proc> sort <array>
  229. /sort {
  230.   1 index length 1 sub -1 1 {
  231.     2 index exch 2 copy get 3 copy    % arr proc arr i arr[i] arr i arr[i]
  232.     0 1 3 index 1 sub {
  233.       3 index 1 index get    % arr proc arr i arr[i] arr imax amax j arr[j]
  234.       2 index 1 index 10 index exec {    % ... amax < arr[j]
  235.     4 2 roll
  236.       } if pop pop
  237.     } for            % arr proc arr i arr[i] arr imax amax
  238.     4 -1 roll exch 4 1 roll put put
  239.   } for pop
  240. } def
  241.  
  242. % Each procedure in this dictionary is called as follows:
  243. %       <encodingtable> proc <glypharray>
  244. /cmapformats mark
  245.   0 {        % Apple standard 1-to-1 mapping.
  246.     6 256 getinterval { } forall 256 packedarray
  247.   } bind
  248.   4 {        % Microsoft/Adobe segmented mapping.
  249.     /etab exch def
  250.     /nseg2 etab 6 getu16 def
  251.     14 /endc etab 2 index nseg2 getinterval def
  252.         % The Apple TrueType documentation omits the 2-byte
  253.         % 'reserved pad' that follows the endCount vector!
  254.     2 add
  255.     nseg2 add /startc etab 2 index nseg2 getinterval def
  256.     nseg2 add /iddelta etab 2 index nseg2 getinterval def
  257.     nseg2 add /idroff etab 2 index nseg2 getinterval def
  258.         % The following hack allows us to properly handle
  259.         % idiosyncratic fonts that start at 0xf000:
  260.     pop
  261.     /firstcode startc 0 getu16 16#ff00 and dup 16#f000 ne { pop 0 } if def
  262.     /putglyph {
  263.       glyphs code 3 -1 roll put /code code 1 add def
  264.     } bind def
  265.         % Do a first pass to compute the size of the glyphs array.
  266.     /numcodes 0 def /glyphs 0 0 2 nseg2 3 sub {
  267.         % Stack: /glyphs numglyphs i2
  268.       /i2 exch def
  269.       /scode startc i2 getu16 def
  270.       /ecode endc i2 getu16 def
  271.       numcodes scode firstcode sub
  272.         % Hack for fonts that have only 0x0000 and 0xf000 ranges
  273.       dup 16#e000 ge { 255 and } if
  274.       exch sub 0 max ecode scode sub 1 add add
  275.       exch 1 index add exch
  276.       numcodes add /numcodes exch def
  277.     } for array def
  278.         % Now fill in the array.
  279.     /numcodes 0 def /code 0 def
  280.     0 2 nseg2 3 sub {
  281.       /i2 exch def
  282.       /scode startc i2 getu16 def
  283.       /ecode endc i2 getu16 def
  284.       numcodes scode firstcode sub
  285.         % Hack for fonts that have only 0x0000 and 0xf000 ranges
  286.       dup 16#e000 ge { 255 and } if
  287.       exch sub 0 max dup { 0 putglyph } repeat
  288.       ecode scode sub 1 add add numcodes add /numcodes exch def
  289.       /delta iddelta i2 gets16 def
  290.       DEBUG {
  291.     (scode=) print scode =only
  292.     ( ecode=) print ecode =only
  293.     ( delta=) print delta =only
  294.     ( droff=) print idroff i2 getu16 =
  295.       } if
  296.       idroff i2 getu16 dup 0 eq {
  297.     pop scode delta add 65535 and 1 ecode delta add 65535 and
  298.     { putglyph } for
  299.       } {    % The +2 is for the 'reserved pad'.
  300.         /gloff exch 14 nseg2 3 mul add 2 add i2 add add def
  301.         0 1 ecode scode sub {
  302.       2 mul gloff add etab exch getu16
  303.       dup 0 ne { delta add 65535 and } if putglyph
  304.     } for
  305.       } ifelse
  306.     } for glyphs /glyphs null def    % for GC
  307.   } bind
  308.   6 {        % Single interval lookup.
  309.     dup 6 getu16 /firstcode exch def dup 8 getu16 /ng exch def
  310.     firstcode ng add array
  311.         % Stack: tab array
  312.         % Fill elements 0 .. firstcode-1 with 0
  313.     0 1 firstcode 1 sub { 2 copy 0 put pop } for
  314.     dup firstcode ng getinterval
  315.         % Stack: tab array subarray
  316.         % Fill elements firstcode .. firstcode+nvalue-1 with glyph values
  317.     0 1 ng 1 sub {
  318.       dup 2 mul 10 add 4 index exch getu16 3 copy put pop pop
  319.     } for pop exch pop
  320.   } bind
  321. .dicttomark readonly def                % cmapformats
  322.  
  323. % <cmaptab> cmaparray <glypharray>
  324. /cmaparray {
  325.   dup 0 getu16 cmapformats exch .knownget {
  326.     DEBUG {
  327.       (cmap: format ) print 1 index 0 getu16 = flush
  328.     } if exec
  329.   } {
  330.     (Can't handle format ) print 0 getu16 = flush
  331.     0 1 255 { } for 256 packedarray
  332.   } ifelse
  333.   DEBUG {
  334.     (cmap: length=) print dup length = dup ==
  335.   } if
  336. } bind def
  337.  
  338. % Each procedure in this dictionary is called as follows:
  339. %       posttable <<proc>> glyphencoding
  340. /postformats mark
  341.   16#00010000  {    % 258 standard Macintosh glyphs.
  342.     pop MacGlyphEncoding
  343.   }
  344.   16#00020000  {    % Detailed map, required by Microsoft fonts.
  345.     /postglyphs exch def
  346.       postglyphs 32 getu16 /numglyphs exch def
  347.       /glyphnames numglyphs 2 mul 34 add def
  348.       [ 0 1 numglyphs 1 sub {
  349.     2 mul 34 add postglyphs exch getu16
  350.     dup 258 lt {
  351.       MacGlyphEncoding exch get
  352.     } {
  353.       dup 32768 ge {
  354.         % According to the published TrueType spec, such values are
  355.         % "reserved for future use", but at least some PDF files
  356.         % produced by the Adobe PDF library contain entries with a
  357.         % value of 16#ffff.
  358.         pop /.notdef
  359.       } {
  360.         258 sub glyphnames exch {
  361.           postglyphs 1 index get 1 add add
  362.         } repeat
  363.         1 add postglyphs exch 2 copy 1 sub get getinterval cvn
  364.         % At least some of Microsoft's TrueType fonts use incorrect
  365.         % (Adobe-incompatible) names for some glyphs.
  366.         % Correct for this here.
  367.         postremap 1 index .knownget { exch pop } if
  368.       } ifelse
  369.     } ifelse
  370.       } for ]
  371.   } bind
  372.   16#00030000  {    % No map.
  373.     pop [ ]
  374.   } bind
  375. .dicttomark readonly def                % postformats
  376.  
  377. % Each procedure in this dictionary is called as follows:
  378. %    <file> <length> -proc- <string|array_of_strings>
  379. % Note that each table must have an even length, because of a strange
  380. % Adobe requirement that each sfnts entry have even length.
  381. /readtables mark
  382.     % Ordinary tables
  383.   (cmap) { .readtable }
  384.   (head) 1 index
  385.   (hhea) 1 index
  386.   (maxp) 1 index
  387.   (name) 1 index
  388.   (OS/2) 1 index
  389.   (post) 1 index
  390.   (vhea) 1 index
  391.     % Big tables
  392.   (glyf) { .readbigtable }
  393.   (loca) 1 index
  394.   (hmtx) 1 index
  395.   (vmtx) 1 index
  396.     % Tables only needed for embedding in PDF files
  397.   (cvt ) { .readtable }
  398.   (fpgm) 1 index
  399.   (prep) 1 index
  400. .dicttomark
  401. % Normally there would be a 'readonly' here, but the ttf2pf utility wants
  402. % to include the 'kern' table as well, so we leave the readtables dictionary
  403. % writable.
  404. def                % readtables
  405.  
  406. % Read a table as a single string.
  407. % <file> <length> .readtable <string>
  408. /.readtable {
  409.   dup dup 1 and add string
  410.         % Stack: f len str
  411.   dup 0 4 -1 roll getinterval
  412.         % Stack: f str str1
  413.   3 -1 roll exch readstring pop pop
  414. } bind def
  415.  
  416. % Read a big table (one that may exceed 64K).
  417. % <file> <length> .readbigtable <string[s]>
  418. /.readbigtable {
  419.   dup 65400 lt {
  420.     .readtable
  421.   } {
  422.     currentuserparams /VMReclaim get -2 vmreclaim
  423.     [ 4 2 roll {
  424.         % Stack: mark ... f left
  425.       dup maxstring le { exit } if
  426.       1 index maxstring string readstring pop 3 1 roll maxstring sub
  427.     } loop .readtable ]
  428.     exch vmreclaim
  429.   } ifelse
  430. } bind def
  431.  
  432. end readonly def                % .loadttfontdict
  433.  
  434. % <tab> .printtab -
  435. /.printtab {
  436.   dup 0 4 getinterval print ( ) print
  437.   dup 8 getu32 =only ( ) print
  438.   12 getu32 =
  439. } bind def
  440.  
  441. % <file> .loadttfonttables -
  442. % Pushes .loadttfontdict & scratch dict on d-stack.
  443. % Defines f, offsets, tables, tabdict, tabs.
  444. /.loadttfonttables {
  445.   .loadttfontdict begin
  446.   40 dict begin
  447.   /f exch def
  448.   /offsets f 12 string readstring pop def
  449.   /tables f offsets 4 getu16 16 mul string readstring pop def
  450.   /tabdict tables length 16 idiv dict def
  451.     % tabs = tables we want to keep, sorted by file position.
  452.   /tabs [ 0 16 tables length 1 sub {
  453.     tables exch 16 getinterval
  454.     DEBUG { dup .printtab } if
  455.     dup 0 4 getinterval readtables 1 index known {
  456.       tabdict exch 2 index put
  457.     } {
  458.       pop pop
  459.     } ifelse
  460.   } for ] {
  461.     exch 8 getu32 exch 8 getu32 lt
  462.   } sort def
  463.     % In certain malformed TrueType fonts, tables overlap.
  464.     % Truncate tables if necessary.
  465.   0 1 tabs length 2 sub {
  466.     dup tabs exch get exch 1 add tabs exch get
  467.     1 index 8 getu32 2 index 12 getu32 add
  468.     1 index 8 getu32 gt {
  469.       (**** Warning: ) print 1 index 0 4 getinterval print
  470.       ( overlaps ) print dup 0 4 getinterval print
  471.       (, truncating.) = flush
  472.       dup 8 getu32 2 index 8 getu32 sub
  473.       2 index 12 3 -1 roll putu32
  474.     } if pop pop
  475.   } for
  476. } bind def
  477.  
  478. % - .readttdata -
  479. % Read data.  Updates offsets, tabs; stores data in tabdict.
  480. /.readttdata {
  481.   /fpos offsets length tables length add def
  482.   /sfpos offsets length tabs length 16 mul add def
  483.   offsets 4 tabs length putu16
  484.   tabs {
  485.     dup 0 4 getinterval /tname exch def
  486.     dup 8 getu32 /tpos exch def
  487.     dup 12 getu32 /tlen exch def
  488.     8 sfpos putu32
  489.     % Skip data between the end of the previous table and
  490.     % the beginning of this one, if any.
  491.     tpos fpos gt {
  492.       f tpos fpos sub () /SubFileDecode filter dup flushfile closefile
  493.       /fpos tpos def
  494.     } if
  495.     f tlen readtables tname get exec
  496.     tabdict tname 3 -1 roll put
  497.     /fpos fpos tlen add def
  498.     % Round up the table length to an even value.
  499.     /sfpos sfpos tlen dup 1 and add add def
  500.   } forall
  501. } bind def
  502.  
  503. % Find the string in a list of strings that includes a given index.
  504. % <strings> <index> .findseg <string> <index'>
  505. /.findseg {
  506.   exch {
  507.     dup length 2 index gt { exch exit } if
  508.     length sub
  509.   } forall
  510. } bind def
  511.  
  512. % - .makesfnts -
  513. % Defines checksum, getloca, head, locatable, numloca, post, sfnts, upem
  514. /.makesfnts {
  515.   .readttdata
  516.   /head tabdict /head get def
  517.   /locatable tabdict /loca get def
  518.   /post tabdict /post .knownget not { null } if def
  519.   /numloca
  520.     locatable dup type /stringtype eq
  521.      { length }
  522.      { 0 exch { length add } forall }
  523.     ifelse    % no def yet
  524.   locatable type /stringtype eq {
  525.     /.indexloca {} def
  526.   } {
  527.     /.indexloca /.findseg load def
  528.   } ifelse
  529.   head 50 getu16 0 ne {
  530.     /getloca {
  531.       2 bitshift locatable exch .indexloca getu32
  532.     } def
  533.     4 idiv 1 sub
  534.   } {
  535.     /getloca {
  536.       dup add locatable exch .indexloca getu16 dup add
  537.     } def
  538.     2 idiv 1 sub
  539.   } ifelse def        % numloca
  540.     % If necessary, re-partition the glyfs.
  541.   tabdict /glyf get dup type /stringtype ne {
  542.     .dividesfnts tabdict /glyf 3 -1 roll put
  543.   } {
  544.     pop
  545.   } ifelse
  546.   /sfnts [
  547.     offsets tabs { concatstrings } forall
  548.     tabs {
  549.       0 4 getinterval tabdict exch get
  550.       dup type /stringtype ne { aload pop } if
  551.     } forall
  552.   ] def
  553. } bind def
  554.  
  555. % <glyfs> .dividesfnts <glyfs'>
  556. /.dividesfnts {
  557.   /glyfs exch def
  558.   /len1 0 glyfs { length add } forall def
  559.         % Determine where to split the glyfs by scanning loca.
  560.         % The very last entry in loca may be bogus.
  561.         % Note that some loca entries may be odd, but we can only
  562.         % split at even positions.
  563.         %
  564.         % Construct splitarray, the array of final lengths of
  565.         % the sfnts entries covering the glyfs (i.e., all but
  566.         % the first and last sfnts entries).
  567.     /prevsplit 0 def
  568.     /prevboundary 0 def
  569.     /splitarray [
  570.       0 1 numloca 1 sub {
  571.     getloca dup prevsplit maxstring add gt {
  572.       prevboundary prevsplit sub exch
  573.       /prevsplit prevboundary def
  574.     } if
  575.     dup 1 and 0 eq { /prevboundary exch def } { pop } ifelse
  576.       } for
  577.       len1 prevsplit sub
  578.     ] def
  579.     currentuserparams /VMReclaim get -2 vmreclaim
  580.     [
  581.         % Re-split the sfnts glyfs strings according to splitarray.
  582.         % We do this by iterating over the final segments defined
  583.         % by splitarray, and constructing them from pieces of the
  584.         % current glyfs strings.  We recycle the current strings
  585.         % when possible, to avoid stressing the allocator.
  586.       /sfnt_idx 0 def
  587.       /strpos 0 def
  588.       /avail () def
  589.       splitarray {
  590.     /seglen exch def
  591.     /segpos 0 def
  592.     avail length seglen ge
  593.       { avail 0 seglen getinterval /avail () def } { seglen string }
  594.     ifelse
  595.     {
  596.       /str glyfs sfnt_idx get def
  597.       /strlen str length def
  598.       /strleft strlen strpos sub def
  599.       seglen segpos sub strleft lt { exit } if
  600.         % Copy the (rest of the) string into the new segment.
  601.         % We know strleft <= segleft.
  602.       dup segpos str strpos strleft getinterval putinterval
  603.       /segpos segpos strleft add def
  604.       /avail str def
  605.       /sfnt_idx sfnt_idx 1 add def
  606.       /strpos 0 def
  607.       segpos seglen eq { exit } if
  608.     } loop
  609.         % Fill up the segment with an initial piece of the next
  610.         % existing glyfs string.  We know strleft > segleft.
  611.     /segleft seglen segpos sub def
  612.     dup segpos str strpos segleft getinterval putinterval
  613.     /strpos strpos segleft add def
  614.       } forall
  615.     ]
  616.     exch vmreclaim
  617. } bind def
  618.  
  619. % - .getpost -
  620. % Uses post, defines glyphencoding
  621. /.getpost {
  622.   /glyphencoding post null eq {
  623.     DEBUG { (post missing) = flush } if [ ]
  624.   } {
  625.     postformats post 0 getu32 .knownget {
  626.       DEBUG {
  627.     (post: format ) print
  628.     post 0 getu16 =only (,) print post 2 getu16 = flush
  629.       } if
  630.       post exch exec
  631.     } {
  632.       DEBUG { (post: unknown format ) print post 0 getu32 = flush } if [ ]
  633.     } ifelse
  634.   } ifelse def
  635. } bind def
  636.  
  637. % - .ttkeys <key> <value> ...
  638. /.ttkeys {
  639.   count /ttkeycount exch def
  640.   /upem head 18 getu16 def
  641.   /FontMatrix matrix
  642.   /FontBBox [ 36 2 42 { head exch gets16 upem div } for ]
  643.   nextxuid
  644.   tabdict /name .knownget {
  645.         % Find the names from the 'name' table.
  646.     /names exch def
  647.     /FontName names 6 findname not { curxuid 16 8 string cvrs } if
  648.       /fontname 1 index def
  649.     /FontInfo mark
  650.       names 0 findname { /Notice exch } if
  651.       names 1 findname { /FamilyName exch } if
  652.       names 4 findname { /FullName exch } if
  653.       names 5 findname { /Version exch } if
  654.   } {
  655.         % No name table, fabricate a FontName.
  656.     /FontName curxuid 16 8 string cvrs
  657.       /fontname 1 index def
  658.     /FontInfo mark
  659.   } ifelse
  660.         % Stack: ... /FontInfo mark key1 value1 ...
  661.   post null ne {
  662.     /ItalicAngle post 4 gets32 65536.0 div
  663.     /isFixedPitch post 12 getu32 0 ne
  664.     /UnderlinePosition post 8 gets16 upem div
  665.     /UnderlineThickness post 10 gets16 upem div
  666.   } if
  667.   counttomark 0 ne { .dicttomark } { pop pop } ifelse
  668.   /XUID [orgXUID 42 curxuid]
  669.   DEBUG {
  670.     tabs { .printtab } forall
  671.     [ sfnts { length } forall ] ==
  672.     count ttkeycount sub array astore dup { == } forall aload pop
  673.   } if
  674.   /sfnts sfnts
  675. } bind def
  676.  
  677. % ---------------- Standard TrueType font loading ---------------- %
  678.  
  679. % - .pickcmap -
  680. % Defines cmapsub, cmaptab
  681. /.pickcmap {
  682.   tabdict /cmap get
  683.         % The Apple cmap format is no help in determining the encoding.
  684.         % Look for a Microsoft table.  If we can't find one,
  685.         % just use the first table, whatever it is.
  686.   dup 4 8 getinterval exch             % the default
  687.   0 1 2 index 2 getu16 1 sub {
  688.     8 mul 4 add 1 index exch 8 getinterval
  689.     DEBUG {
  690.       (cmap: platform ) print dup 0 getu16 =only
  691.       ( encoding ) print dup 2 getu16 = flush
  692.     } if
  693.     dup 0 getu16 3 eq { exch 3 -1 roll pop exit } if pop
  694.   } for
  695.         % Stack: subentry table
  696.   /cmapsub 2 index def
  697.   exch 4 getu32 1 index length 1 index sub getinterval
  698.   /cmaptab exch def
  699. } bind def
  700.  
  701. % <glyph> .nname <_name>
  702. /.nname {
  703.   =string cvs (_) exch concatstrings cvn
  704. } bind def
  705.  
  706. % - .charkeys /CharStrings <charstrings> /Encoding <encoding>
  707. % Resets glyphencoding
  708. /.charkeys {
  709.   DEBUG {
  710.     (glyphencoding: length=) print glyphencoding dup length = === flush
  711.   } if
  712.         % Hack: if there is no usable post table but the cmap uses
  713.         % the Microsoft Unicode encoding, use ISOLatin1Encoding.
  714.   glyphencoding length 0 eq cmapsub 0 4 getinterval <00030001> eq and {
  715.     /glyphencoding ISOLatin1Encoding dup length array copy def
  716.   } if
  717.         % If necessary, fabricate additional glyphencoding entries
  718.         % to cover all of loca, or truncate glyphencoding.
  719.   glyphencoding length numloca lt {
  720.     /glyphencoding [ glyphencoding aload pop
  721.     counttomark 1 numloca 1 sub { .nname } for ] def
  722.   } {
  723.     /glyphencoding glyphencoding 0 numloca getinterval def
  724.   } ifelse
  725.         % Some badly designed Chinese fonts have a post table
  726.         % in which all glyphs other than 0 are named .null.
  727.         % Use CharStrings to keep track of the reverse map from
  728.         % names to glyphs, and don't let any name be used for
  729.         % more than one glyph.
  730.   /CharStrings glyphencoding dup length 1 add dict    % +1 for .notdef
  731.     0 1 3 index length 1 sub {
  732.         % Stack: glyphencoding dict index
  733.       2 index 1 index get 2 index 1 index known {
  734.         % The same name maps to more than one glyph.
  735.         % Change the name.
  736.     pop dup .nname 3 index 2 index 2 index put
  737.       } if
  738.       2 index exch 3 -1 roll put
  739.     } for exch pop
  740.         % If there is no .notdef entry, map it to glyph 0.
  741.   dup /.notdef known not { dup /.notdef 0 put } if
  742.   readonly
  743.   /Encoding
  744.     [ cmaptab cmaparray dup length 256 gt { 0 256 getinterval } if
  745.     { glyphencoding exch get } forall
  746.     counttomark 256 exch sub { /.notdef } repeat ]
  747.   DEBUG { (Encoding: ) print dup === flush } if
  748. } bind def
  749.  
  750. % -mark- <key> <value> ... .definettfont <font>
  751. /.definettfont {
  752.   /FontType 42
  753.   /PaintType 0
  754.   DEBUG {
  755.     (numloca=) print numloca =
  756.   } if
  757.   .dicttomark
  758.   end end dup /FontName get exch definefont
  759. } bind def
  760.  
  761. % <file> .loadttfont <type42font>
  762. /.loadttfont {
  763.   .loadttfonttables
  764.   .makesfnts
  765.   .getpost
  766.   .pickcmap
  767.   mark
  768.   .charkeys
  769.   .ttkeys
  770.   .definettfont
  771. } bind def
  772.  
  773. % ---------------- CIDFontType 2 font loading ---------------- %
  774.  
  775. % Create a string with N CIDs from the top of the stack.
  776. % <cid1> ... <cidN> <N> .makecidmap <string>
  777. /.makecidmap {
  778.   dup 2 mul string dup 3 -1 roll 1 sub 2 mul -2 0 {
  779.         % Stack: cids str str i2
  780.     2 copy 5 index -8 bitshift put
  781.     1 add 4 -1 roll 16#ff and put dup
  782.   } for pop
  783. } bind def
  784.  
  785. % -mark- <key> <value> ... .definettcidfont <font>
  786. /.definettcidfont {
  787.   /CIDFontName fontname
  788.   /CIDFontType 2
  789.   /CIDSystemInfo mark
  790.     /Registry (Adobe)
  791.     /Ordering (Japan1)        % adhoc
  792.     /Supplement 0
  793.   .dicttomark
  794.   /CharStrings mark /.notdef 0 .dicttomark
  795.         % The cmap isn't of any use even if it is present.
  796.         % Just construct an identity CIDMap covering all the glyphs.
  797.   mark 0 1 numloca 1 sub { } for
  798.   counttomark /cidcount exch def
  799.   cidcount maxstring le {
  800.         % Use a single string.
  801.     cidcount .makecidmap exch pop
  802.   } {
  803.         % We must use 2 strings.
  804.     maxstring .makecidmap counttomark 1 add 1 roll
  805.     counttomark .makecidmap exch pop exch 2 array astore
  806.   } ifelse
  807.   /CIDMap exch
  808.   /CIDCount cidcount
  809.   /GDBytes 2
  810.   .dicttomark
  811.   end end dup /CIDFontName get exch /CIDFont defineresource
  812. } bind def
  813.  
  814. % <file> .loadttcidfont <cidtype2font>
  815. /.loadttcidfont {
  816.   .loadttfonttables
  817.   .makesfnts
  818.     % CIDFontType2 fonts don't have a cmap: they are indexed by CID.
  819.   mark
  820.   .ttkeys
  821.   .definettcidfont
  822. } bind def
  823.  
  824. % ---------------- PDF TrueType font loading ---------------- %
  825.  
  826. % Strictly speaking, this code should be loaded only if we have a PDF
  827. % interpreter, but it's so closely tied to the rest of the code in this
  828. % file that we always include it.
  829.  
  830. % <plat+enc> .findcmap <subtable> true
  831. % <plat+enc> .findcmap false
  832. /.findcmap {
  833.   false exch tabdict /cmap get
  834.         % Some fonts have multiple cmaps with the same platform and
  835.         % encoding.  Use the first one we find.
  836.   0 1 2 index 2 getu16 1 sub {
  837.         % Stack: false plat+enc cmap index
  838.     8 mul 4 add 1 index exch 8 getinterval 
  839.     dup 0 4 getinterval 3 index eq {
  840.       4 getu32 1 index exch 1 index length 1 index sub getinterval
  841.       4 -1 roll not 4 2 roll exit
  842.     } if pop
  843.   } for
  844.         % Stack: false plat+enc cmap || subtable true plat+enc cmap
  845.   pop pop
  846. } bind def
  847.  
  848. % <subcmap> <chartoglyphmap> .pdfmapchars
  849. %   /CharStrings <charstrings> /Encoding <encoding>
  850. % Uses encoding
  851. /.pdfmapchars {
  852.   exch cmaparray /cmapencoding exch def
  853.     % Invert glyphencoding (post).
  854.   /inversepost glyphencoding length dict def
  855.   0 1 glyphencoding length 1 sub {
  856.     glyphencoding 1 index get exch inversepost 3 1 roll put
  857.   } for
  858.   /CharStrings mark 3 -1 roll {
  859.     dup type /arraytype eq {
  860.       exch /ch exch def { ch exch .pdfaddchar } forall
  861.     } {
  862.       .pdfaddchar
  863.     } ifelse
  864.   } forall
  865.     % Add a .notdef => 0 entry if needed.  Per Adobe's spec,
  866.     % .dicttomark (>>) adds pairs in top-to-bottom order.
  867.   /.notdef 0
  868.   .dicttomark
  869.   /Encoding encoding
  870. } bind def
  871. % <charname> <charcode> .pdfaddchar <charname> <glyph#>
  872. % <charname> <charcode> .pdfaddchar -
  873. /.pdfaddchar {
  874.   dup cmapencoding length lt {
  875.     cmapencoding exch get dup 0 eq {
  876.       pop .pdfaddpost
  877.     } if
  878.   } {
  879.     pop .pdfaddpost
  880.   } ifelse
  881. } bind def
  882. % <charname> .pdfaddpost <charname> <glyph#>
  883. % <charname> .pdfaddpost -
  884. /.pdfaddpost {
  885.   inversepost 1 index .knownget not { pop } if
  886. } bind def
  887.  
  888. % - .pdfcharkeys /CharStrings <charstrings> /Encoding <encoding>
  889. /.pdfcharkeys {
  890.     % The following algorithms are per the PDF Reference, Second Edition
  891.     % (PDF 1.3 reference manual).
  892.   encoding null eq {
  893.     .charkeys        % use default algorithm
  894.   } {
  895.     <00030001> .findcmap {
  896.       AdobeGlyphList .pdfmapchars
  897.     } {
  898.       <00010000> .findcmap {
  899.     .romanmacdict .pdfmapchars
  900.       } {
  901.     .charkeys    % use default algorithm
  902.       } ifelse
  903.     } ifelse
  904.   } ifelse
  905. } bind def
  906.  
  907. % <file> <encoding|null> .loadpdfttfont <type42font>
  908. /.loadpdfttfont {
  909.   exch .loadttfonttables
  910.   /encoding exch def
  911.   .makesfnts
  912.   .getpost
  913.   .pickcmap
  914.   mark
  915.   .pdfcharkeys
  916.   .ttkeys
  917.   .definettfont
  918. } bind def
  919.